package main

//go   传值与传址
//https://github.com/astaxie/build-web-application-with-golang/blob/master/zh/02.5.md

//最大的疑惑是：PaintItBlack方法。（未解决）
//bl是切片，作为reciver的时候，它不是一个拷贝吗？如果是拷贝的话，那么对bl的操作，只是对拷贝的操作而已。
//  难道是因为bl 是切片，切片默认传递方式是传址。  ？？？？  对比发现，好像也不是。
//SetColorTest 是一个对比，发现SetColorTest的reciver是一个拷贝

import "fmt"

const (
	WHITE = iota
	BLACK
	BLUE
	RED
	YELLOW
)

type Color byte

type Box struct {
	width, height, depth float64
	color                Color
}

type BoxList []Box //a slice of boxes

func (b Box) Volume() float64 {
	return b.width * b.height * b.depth
}

// 对于struct的对象，简单的理解，定时是 reciver 带* 相当于php中的&符号。其他用法都一样。
//调用SetColor不需要加  &  函数内部，访问属性，也不需要加*   与例证2对比。
func (b *Box) SetColor(c Color) {
	b.color = c
}
func (b Box) SetColorTest(c Color) {
	b.color = c
}

func (bl BoxList) BiggestColor() Color {
	v := 0.00
	k := Color(WHITE)
	for _, b := range bl {
		if bv := b.Volume(); bv > v {
			v = bv
			k = b.color
		}
	}
	return k
}

func (bl BoxList) PaintItBlack() {
	for i := range bl {
		bl[i].SetColor(BLACK)
	}
}

func (c Color) String() string {
	strings := []string{"WHITE", "BLACK", "BLUE", "RED", "YELLOW"}
	return strings[c]
}

type Scores []int

func (s Scores) addValue(v int) int {
	s = append(s, v)
	return v
}

//例证2
//对比，下面的这个就能改变。   但是内部需要使用*s
func (s *Scores) addValueTest(v int) int {
	*s = append(*s, v)
	return v
}

func main() {
	boxes := BoxList{
		Box{4, 4, 4, RED},
		Box{10, 10, 1, YELLOW},
		Box{1, 1, 20, BLACK},
		Box{10, 10, 1, BLUE},
		Box{10, 30, 1, WHITE},
		Box{20, 20, 20, YELLOW},
	}
	box := Box{1, 1, 1, RED}

	//	sc := make(scores, 1, 10)
	sc := Scores{1, 2, 3}

	sc.addValue(11)
	sc.addValue(22)
	sc = append(sc, 4, 5)
	for _, val := range sc {
		fmt.Println(val)
	}

	fmt.Println("the box color is ", box.color.String())
	box.SetColorTest(BLUE)
	fmt.Println("the box color is ", box.color.String())

	fmt.Printf("We have %d boxes in our set\n", len(boxes))
	fmt.Println("The volume of the first one is", boxes[0].Volume(), "cm³")
	fmt.Println("The color of the last one is", boxes[len(boxes)-1].color.String())
	fmt.Println("The biggest one is", boxes.BiggestColor().String())

	fmt.Println("Let's paint them all black")
	boxes.PaintItBlack()
	fmt.Println("The color of the second one is", boxes[1].color.String())

	fmt.Println("Obviously, now, the biggest one is", boxes.BiggestColor().String())
}
